/**
 * 简化版调度器实现
 * 主要功能：
 * 1. 支持优先级调度（使用最小堆）
 * 2. 使用 postMessage 实现宏任务
 * 3. 支持任务中断（unstable_shouldYield）
 * 4. 支持任务恢复（callback 返回函数）
 * 5. 支持取消任务
 */

// ============ 优先级定义 ============
// 数字越小，优先级越高
const ImmediatePriority = 1; // 立即执行
const UserBlockingPriority = 2; // 用户阻塞型（如点击事件）
const NormalPriority = 3; // 正常优先级
const LowPriority = 4; // 低优先级
const IdlePriority = 5; // 空闲优先级

// ============ 超时时间定义 ============
// 优先级越高，超时时间越短，越容易过期
const IMMEDIATE_PRIORITY_TIMEOUT = -1; // 立即过期
const USER_BLOCKING_PRIORITY_TIMEOUT = 250; // 250ms
const NORMAL_PRIORITY_TIMEOUT = 5000; // 5s
const LOW_PRIORITY_TIMEOUT = 10000; // 10s
const IDLE_PRIORITY_TIMEOUT = 1073741823; // 永不过期

// ============ 任务类型定义 ============
type Task = {
  id: number; // 任务ID
  callback: Function | null; // 任务回调函数
  priorityLevel: number; // 优先级
  expirationTime: number; // 过期时间（用于最小堆排序）
  sortIndex: number; // 排序索引
};

// ============ 全局变量 ============
let taskQueue: Task[] = []; // 任务队列（最小堆结构）
let taskIdCounter = 1; // 任务ID计数器
let isHostCallbackScheduled = false; // 是否已经调度了宏任务
let isPerformingWork = false; // 是否正在执行任务
let currentTask: Task | null = null; // 当前正在执行的任务
let startTime = -1; // 当前宏任务开始时间
const frameInterval = 5; // 时间片大小：5ms

// ============ 获取当前时间 ============
function getCurrentTime(): number {
  return performance.now();
}



// ============ postMessage 宏任务实现 ============
const channel = new MessageChannel();
const port = channel.port2;

// 监听消息，执行宏任务
channel.port1.onmessage = () => {
  // 宏任务执行的入口函数
  performWorkUntilDeadline();
};

/**
 * 触发一个宏任务
 */
function schedulePerformWorkUntilDeadline(): void {
  port.postMessage(null);
}

/**
 * 宏任务执行函数
 * 会在浏览器宏任务队列中执行
 */
function performWorkUntilDeadline(): void {
  if (isHostCallbackScheduled) {
    const currentTime = getCurrentTime();
    startTime = currentTime; // 记录宏任务开始时间

    let hasMoreWork = true;
    try {
      // 执行工作循环，返回是否还有更多任务
      hasMoreWork = workLoop(currentTime);
    } finally {
      if (hasMoreWork) {
        // 如果还有任务，继续触发下一个宏任务
        schedulePerformWorkUntilDeadline();
      } else {
        // 没有任务了，重置状态
        isHostCallbackScheduled = false;
      }
    }
  }
}

// ============ 核心调度逻辑 ============
/**
 * 工作循环：从任务队列中取出任务并执行
 * @returns 是否还有更多任务
 */
function workLoop(initialTime: number): boolean {
  let currentTime = initialTime;
  currentTask = peek(taskQueue); // 取出优先级最高的任务

  while (currentTask !== null) {
    // 判断是否需要中断：
    // 1. 任务还没过期（expirationTime > currentTime）
    // 2. 并且当前宏任务执行时间超过了 5ms（shouldYieldToHost）
    if (currentTask.expirationTime > currentTime && unstable_shouldYield()) {
      // 需要中断，退出循环，把控制权还给浏览器
      break;
    }

    const callback = currentTask.callback;
    if (typeof callback === 'function') {
      currentTask.callback = null; // 先清空 callback
      const didUserCallbackTimeout = currentTask.expirationTime <= currentTime; // 任务是否过期

      // 执行任务回调
      // callback 可能返回一个函数，表示任务被中断，需要继续执行
      const continuationCallback = callback(didUserCallbackTimeout);

      currentTime = getCurrentTime(); // 更新当前时间

      if (typeof continuationCallback === 'function') {
        // 返回了函数，说明任务被中断了，需要恢复执行
        // 把返回的函数重新赋值给 callback，等待下次执行
        currentTask.callback = continuationCallback;
      } else {
        // 任务执行完成，从队列中删除
        if (currentTask === peek(taskQueue)) {
          // 确保当前任务还是堆顶任务（没有插入更高优先级的任务）
          pop(taskQueue);
        }
      }
    } else {
      // callback 不是函数，直接删除该任务
      pop(taskQueue);
    }

    // 取出下一个任务
    currentTask = peek(taskQueue);
  }

  // 返回是否还有任务
  if (currentTask !== null) {
    return true; // 还有任务，需要继续调度
  } else {
    return false; // 没有任务了
  }
}

// ============ 对外暴露的 API ============
/**
 * 调度一个任务
 * @param priorityLevel 优先级
 * @param callback 任务回调函数
 * @returns 返回任务对象，可用于取消任务
 */
function unstable_scheduleCallback(
  priorityLevel: number,
  callback: Function
): Task {
  const currentTime = getCurrentTime();
  const startTime = currentTime; // 任务开始时间

  // 根据优先级计算超时时间
  let timeout: number;
  switch (priorityLevel) {
    case ImmediatePriority:
      timeout = IMMEDIATE_PRIORITY_TIMEOUT;
      break;
    case UserBlockingPriority:
      timeout = USER_BLOCKING_PRIORITY_TIMEOUT;
      break;
    case IdlePriority:
      timeout = IDLE_PRIORITY_TIMEOUT;
      break;
    case LowPriority:
      timeout = LOW_PRIORITY_TIMEOUT;
      break;
    case NormalPriority:
    default:
      timeout = NORMAL_PRIORITY_TIMEOUT;
      break;
  }

  // 计算任务过期时间
  const expirationTime = startTime + timeout;

  // 创建任务对象
  const newTask: Task = {
    id: taskIdCounter++,
    callback,
    priorityLevel,
    expirationTime,
    sortIndex: expirationTime, // 使用过期时间作为排序依据
  };

  // 将任务加入队列（最小堆）
  push(taskQueue, newTask);

  // 如果当前没有调度宏任务，且没有正在执行任务，则开始调度
  if (!isHostCallbackScheduled && !isPerformingWork) {
    isHostCallbackScheduled = true;
    schedulePerformWorkUntilDeadline(); // 触发宏任务
  }

  return newTask;
}

/**
 * 判断是否应该中断当前任务
 * 如果当前宏任务执行时间超过 5ms，则应该中断
 */
function unstable_shouldYield(): boolean {
  const currentTime = getCurrentTime();
  const timeElapsed = currentTime - startTime; // 当前宏任务已执行时间
  return timeElapsed >= frameInterval; // 超过 5ms 则中断
}

/**
 * 取消一个任务
 * @param task 要取消的任务
 */
function unstable_cancelCallback(task: Task): void {
  // 将任务的 callback 置为 null 即可
  // 不能直接从堆中删除（数组堆只能删除堆顶元素）
  // 在 workLoop 中会检查 callback 是否为 null，为 null 则删除
  task.callback = null;
}

// ============ 导出 API ============
export {
  unstable_scheduleCallback,
  unstable_shouldYield,
  unstable_cancelCallback,
  ImmediatePriority,
  UserBlockingPriority,
  NormalPriority,
  LowPriority,
  IdlePriority,
};


// ============ 最小堆操作 ============
/**
 * 向最小堆中插入任务
 * 堆的特性：父节点的值 <= 子节点的值
 * 插入后需要向上调整（siftUp）
 */
function push(heap: Task[], node: Task): void {
  const index = heap.length;
  heap.push(node);
  siftUp(heap, node, index);
}

/**
 * 从最小堆中取出堆顶元素（最小值）
 * 取出后需要向下调整（siftDown）
 */
function pop(heap: Task[]): Task | null {
  if (heap.length === 0) {
    return null;
  }
  const first = heap[0]; // 堆顶元素（最小值）
  const last = heap.pop()!; // 取出最后一个元素
  if (last !== first) {
    heap[0] = last; // 把最后一个元素放到堆顶
    siftDown(heap, last, 0); // 向下调整
  }
  return first;
}

/**
 * 查看堆顶元素（不删除）
 */
function peek(heap: Task[]): Task | null {
  return heap.length === 0 ? null : heap[0];
}

/**
 * 向上调整堆（用于插入操作）
 * 如果子节点比父节点小，则交换位置
 */
function siftUp(heap: Task[], node: Task, i: number): void {
  let index = i;
  while (index > 0) {
    const parentIndex = (index - 1) >>> 1; // 父节点索引 = (index - 1) / 2
    const parent = heap[parentIndex];
    // 如果当前节点比父节点小，则交换
    if (compare(parent, node) > 0) {
      heap[parentIndex] = node;
      heap[index] = parent;
      index = parentIndex;
    } else {
      return; // 已经满足堆的性质
    }
  }
}

/**
 * 向下调整堆（用于删除操作）
 * 如果父节点比子节点大，则交换位置
 */
function siftDown(heap: Task[], node: Task, i: number): void {
  let index = i;
  const length = heap.length;
  const halfLength = length >>> 1; // 只需要调整到一半（因为后半部分是叶子节点）

  while (index < halfLength) {
    const leftIndex = (index + 1) * 2 - 1; // 左子节点索引 = 2 * index + 1
    const left = heap[leftIndex];
    const rightIndex = leftIndex + 1; // 右子节点索引 = 2 * index + 2
    const right = heap[rightIndex];

    // 找出左右子节点中较小的那个
    if (compare(left, node) < 0) {
      // 左子节点比当前节点小
      if (rightIndex < length && compare(right, left) < 0) {
        // 右子节点比左子节点还小，与右子节点交换
        heap[index] = right;
        heap[rightIndex] = node;
        index = rightIndex;
      } else {
        // 与左子节点交换
        heap[index] = left;
        heap[leftIndex] = node;
        index = leftIndex;
      }
    } else if (rightIndex < length && compare(right, node) < 0) {
      // 右子节点比当前节点小，与右子节点交换
      heap[index] = right;
      heap[rightIndex] = node;
      index = rightIndex;
    } else {
      return; // 已经满足堆的性质
    }
  }
}

/**
 * 比较两个任务的优先级
 * 返回值：< 0 表示 a 优先级更高，> 0 表示 b 优先级更高
 */
function compare(a: Task, b: Task): number {
  // 先按 sortIndex（过期时间）排序
  const diff = a.sortIndex - b.sortIndex;
  // 如果过期时间相同，则按 id 排序（先进先出）
  return diff !== 0 ? diff : a.id - b.id;
}

// ============ 使用示例 ============
/*
// 示例1：简单的任务调度
const task1 = unstable_scheduleCallback(NormalPriority, () => {
  console.log('执行任务1');
});

// 示例2：任务中断与恢复
const task2 = unstable_scheduleCallback(NormalPriority, (didTimeout) => {
  console.log('开始执行任务2，是否超时：', didTimeout);

  // 模拟耗时操作
  let i = 0;
  while (i < 1000000) {
    i++;
    // 检查是否应该中断
    if (unstable_shouldYield()) {
      console.log('任务2被中断，需要恢复执行');
      // 返回一个函数，表示需要继续执行
      return (didTimeout) => {
        console.log('任务2恢复执行');
        // 继续执行剩余工作...
      };
    }
  }

  console.log('任务2执行完成');
  // 返回 undefined 或不返回，表示任务完成
});

// 示例3：取消任务
const task3 = unstable_scheduleCallback(LowPriority, () => {
  console.log('这个任务不会执行');
});
unstable_cancelCallback(task3); // 取消任务

// 示例4：不同优先级的任务
unstable_scheduleCallback(ImmediatePriority, () => {
  console.log('立即执行的任务');
});

unstable_scheduleCallback(UserBlockingPriority, () => {
  console.log('用户阻塞型任务（如点击事件）');
});

unstable_scheduleCallback(NormalPriority, () => {
  console.log('普通优先级任务');
});

unstable_scheduleCallback(LowPriority, () => {
  console.log('低优先级任务');
});

unstable_scheduleCallback(IdlePriority, () => {
  console.log('空闲时执行的任务');
});
*/


